<?php

declare(strict_types=1);

namespace app\admin;

use app\BaseController;
use think\facade\View;
use think\facade\Config;
use app\system\model\Role;
use app\system\model\RoleDept;
use app\system\model\Dept;
use app\admin\middleware\Check;

/**
 * XP系统基础控制器
 * 所有XP系统的控制器都应该继承这个控制器
 */
abstract class BaseXpController extends BaseController
{

    /**
     * XP系统配置
     * @var array
     */
    public $xpConfig = [];

    /**
     * 菜单文件
     * @var array
     */
    protected $menuFiles = [];

    /**
     * 事件
     * @var array
     */
    protected $events = [];

    /**
     * 登录用户信息
     */
    public $user = null;

    /**
     * 初始化
     */
    public function initialize()
    {
        parent::initialize();
        // 中间件
        $this->middleware = [Check::class];
        // XP 配置
        $this->xpConfig = Config::get('xp');
        View::assign('xpConfig', $this->xpConfig);
        // 域名
        View::assign('domain', DOMAIN);
        // 菜单文件
        $this->menuFiles = $this->getAppFiles();
        // 读取事件
        $this->getEvents();
    }

    /**
     * 获取数据权限
     */
    protected function dataScope()
    {
        if ($this->user && $this->user->role_id) {
            $role = Role::find($this->user->role_id);
            if ($role) {
                switch ($role['data_scope']) {
                    case 2:
                        // 自定义数据权限
                        $arr = RoleDept::where('role_id', $role->id)->column('dept_id');
                        define('DATA_SCOPE_DEPT_CUSTOM', $arr);
                        break;
                    case 3:
                        // 本部门数据权限
                        define('DATA_SCOPE_DEPT', true);
                        break;
                    case 4:
                        // 本部门及以下数据权限
                        $arr = Dept::getDeptId($this->user->dept_id);
                        define('DATA_SCOPE_DEPT_ALL', $arr);
                        break;
                    case 5:
                        // 仅本人数据权限
                        define('DATA_SCOPE_SELF', true);
                        break;
                    default:
                        break;
                }
            }
        }
    }

    /**
     * 触发事件 (可跨应用执行事件)
     * @param string $event 事件名称
     * @param array $params 参数
     * @return array 事件返回值数组
     */
    public function trigger($event, $params = [])
    {
        $events = $this->events;
        $result = [];
        if ($events && isset($events[$event])) {
            foreach ($events[$event] as $value) {
                [$className, $methodName] = explode('@', $value);
                if (class_exists($className) && method_exists($className, $methodName)) {
                    $object = new $className();
                    $result[] = call_user_func([$object, $methodName], $params);
                }
            }
        }
        return $result;
    }

    /**
     * 读取事件
     */
    protected function getEvents()
    {
        $events = [];
        if ($this->menuFiles) {
            foreach ($this->menuFiles as $file) {
                $menu = require $file;
                if (isset($menu['events'])) {
                    $events[] = $menu['events'];
                }
            }
        }
        $this->events = $this->mergeSameKeys($events);
    }

    /**
     * 合并相同键值的数组
     * @param array $array 待合并的数组
     * @return array 合并后的数组
     */
    protected function mergeSameKeys($array)
    {
        $result = [];
        foreach ($array as $subArray) {
            foreach ($subArray as $key => $values) {
                if (isset($result[$key])) {
                    $result[$key] = array_merge($result[$key], $values);
                } else {
                    $result[$key] = $values;
                }
            }
        }
        return $result;
    }

    /**
     * 获取应用菜单文件
     * @return array 菜单文件数组
     */
    protected function getAppFiles()
    {
        $files = [];
        $dir = base_path();
        $handle = opendir($dir);
        while (false !== ($entry = readdir($handle))) {
            if ($entry != "." && $entry != "..") {
                $filePath = $dir . $entry;
                if (is_dir($filePath)) {
                    $menuFile = $filePath . '/config/menu.php';
                    $lockFile = $filePath . '/config/delete.lock'; // 存在时则为删除状态
                    if (!file_exists($lockFile) && file_exists($menuFile)) {
                        $files[] = $menuFile;
                    }
                }
            }
        }
        closedir($handle);
        return $files;
    }

    /**
     * 加密
     * @param string $data 待加密的数据
     * @return string 加密后的数据
     */
    public function encrypt($data)
    {
        openssl_public_encrypt($data, $encryptedData, $this->xpConfig['public_key'], OPENSSL_PKCS1_OAEP_PADDING);
        return base64_encode($encryptedData);
    }
}
